use strict;
use warnings;
use POE qw(
    Component::IRC 
    Component::IRC::Plugin::CPAN::LinksToDocs
    Component::IRC::Plugin::URI::Find
    Component::IRC::Plugin::Google::Calculator
    Component::IKC::Server
    Component::IKC::Specifier
);
use Data::Dumper;
use POE::Component::IKC::ClientLite;
use DateTime;
use constant PATH => $ENV{HOME} ."/irc/";
use Encode qw/encode decode/;
use URI;
use URI::Escape;
use YAML::Syck;
use Web::Scraper;
use LWP::UserAgent;
use Net::Twitter;
use Me2day;
use Command::Basic;

my $config;
if (-f 'config.yaml') {
    $config = LoadFile('config.yaml');
}
else {
    print "Can't load config.yaml\n";
    exit;
}

my $nickname = $config->{bot}->{nickname};
my $ircname = $config->{bot}->{ircname};
my $server = $config->{bot}->{server};

my $lang = "ko";
my $google_url = 'http://www.google.com/search?hl='.$lang.'&q=';

my $ping_time = 0;

my @channels = @{ $config->{bot}->{channels} };
my %modules = map { $_ => 1 } @{ $config->{bot}->{modules} };

my $base_url = "";

my $me2day;
if(exists($modules{'me2day'})) {
    $me2day = Me2day->new(
        username => $config->{me2day}->{username},
        user_key => $config->{me2day}->{user_key},
        app_key  => $config->{me2day}->{app_key},
    );
}

my $relay;
if(exists($modules{'relay'})) {
    $relay = 1;
}

my $name = "Clientt$$";

unless (-d PATH) {
    mkdir PATH;
    print STDERR "Created Directory ".PATH."\n";
}

my %func_public_cmd = (
	kick	=> \&cmd_public_kick,
	j2k		=> \&cmd_public_j2k,
	help	=> \&cmd_public_help,
	dic		=> \&cmd_public_dic,
	map		=> \&cmd_public_map,
	search	=> \&cmd_public_search,
	lang	=> \&cmd_public_lang,
	twitter => \&cmd_public_twitter,
	me2day  => \&cmd_public_me2day,
);

my $command_public = Command::Basic->new(
    config	=> $config,
);

POE::Component::IKC::Server->spawn(
    port => 31338,
    name => 'AppServer',
);

POE::Session->create(
    inline_states => {
        _start        => \&service_start,
        update        => \&service_update,
        did_something => \&service_response,
        rss_update    => \&service_rss_update,
      }
);

my $remote;    
my $irc = POE::Component::IRC->spawn( 
				      nick => $nickname,
				      ircname => $ircname,
				      server => $server,
				      ) or die "Oh noooo! $!";


POE::Session->create(
    package_states => [
        main => [ qw(_default _start irc_001 irc_public irc_msg irc_urifind_uri) ],
    ],
    heap => { irc => $irc },
);

POE::Kernel->run();

sub service_start {
    my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];

    my $service_name = "application";
    $kernel->alias_set($service_name);
    $kernel->call( IKC => publish => $service_name, ["update"] );
    $kernel->call( IKC => publish => $service_name, ["rss_update"] );
}

sub service_update {
    my ( $kernel, $heap, $request ) = @_[ KERNEL, HEAP, ARG0 ];

    $kernel->delay_set( did_something => 1, $request );
}

sub service_response {
    my ( $kernel, $heap, $res ) = @_[ KERNEL, HEAP, ARG0 ];
    my @data = @{ $res };
    $irc->yield( privmsg => "#perl-kr" => $data[0] );
}

sub service_rss_update {
    my ( $kernel, $heap, $request ) = @_[ KERNEL, HEAP, ARG0 ];
	warn $request;
    $irc->yield( privmsg => "#perl-kr" => $request );
}

sub _start {
    my $heap = $_[HEAP];
    
    my $irc = $heap->{irc};

    $irc->yield( register => 'all' );
    $irc->plugin_add(	'LinksToDocs' => POE::Component::IRC::Plugin::CPAN::LinksToDocs->new );
    $irc->plugin_add(   'UriFind' =>     POE::Component::IRC::Plugin::URI::Find->new         );
    $irc->plugin_add(   'GoogleCalc' =>  POE::Component::IRC::Plugin::Google::Calculator->new );
    $irc->yield( connect => { } );
    return;
}

sub irc_001 {
    my $sender = $_[SENDER];
    
    my $irc = $sender->get_heap();
    
    print "Connected to ", $irc->server_name(), "\n";

    $irc->yield( join => "#$_" ) for @channels;
    return;
}

sub irc_msg {
    my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];
    my $nick = ( split /!/, $who)[0];
    my $me = $where->[0];

    my $irc = $sender->get_heap();

    my ($channel,$target);
    my @block;
    if ($what =~ /^!([a-z]+)\s?(.*?)?$/) {
	my ($command, $desc) = ($1,$2);
	if ($command eq 'blah') {
	    @block = split /\s+/, $desc;
	    $channel = shift @block;
	    my $blah = join(" ", @block);
	    if ($channel && $channel =~ /^\#.*/ && $blah) {
		$irc->yield( privmsg => $channel => $blah );
	    }
	}
	elsif ($command eq 'kick') {
	    ($channel, $target) = split /\s+/, $desc;
            unless ($target) {
                $irc->yield( privmsg => $nick => $config->{command}->{kick} );
            } else {
                $irc->yield( kick => $channel => $target );
            }
	}
	elsif ($command eq 'oper') {
	    ($channel, $target) = split /\s+/, $desc;
            $irc->yield( mode => $channel => "+oo" => $target );
	}
        elsif ($command eq 'reload') {  # Config Reloader
            if (-f "config.yaml") {
                $config = LoadFile("config.yaml");
                $irc->yield( privmsg => $nick => "reloaded config file" );
            }
        }
    }
}

sub irc_public {
    my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];
    my $nick = ( split /!/, $who )[0];
    my $channel = $where->[0];

    $channel =~ s/#//;

    # Filtering by aero                                                                                                                                
    my $str = decode("euc-kr", encode("euc-kr", decode("utf-8", $what)));
    return 0 if $str =~ /^\x{3151}/;

    if($relay and !$remote) {
        $remote = create_ikc_client(
            port => 31337,
            name => $name,
            timeout => 1,
        );
    }
    
    if($relay) {
        $remote->post_respond(
            'apphanirc/update',
            encode("cp949", decode("utf-8","[freenode] $nick: ".$what))
        );
    }
    
    unless(-d PATH.$channel) {
		print STDERR "Created Directory ". PATH.$channel . " for IRC Channel ".$channel."\n";
		mkdir PATH.$channel;
    }

    my $time = DateTime->now( time_zone => 'Asia/Tokyo' );

    my $filepath = PATH.$channel."/".$time->ymd.".log";
    open my $fh, ">>", $filepath;
    my $desc = "[".$time->hms."] <".$nick."> ". $what."\n";
    print $fh $desc;
    print $desc;
    close $fh;   

    my $irc = $sender->get_heap();

    # $command, $desc

	$command_public->command($sender, $who, $where, $what);

#    if ($what =~ /^!([a-z0-9]+)\s?(.*?)?$/) {
#		my ($command, $desc) = ($1, $2);
#
#		if(exists($func_public_cmd{$command})) {
#			if(!$desc and !($command =~ /(?:help|nolog)/)) {
#				$irc->yield( privmsg => "#".$channel => $nick." : ".$config->{command}->{$command} );
#			}
#			else {
#				$func_public_cmd{$command}->($desc, $channel, $nick);
#			}
#		}
#    }
}
    
sub _default {
    my ($event, $args) = @_[ARG0 .. $#_];
    my @output = ( "$event: " );

    irc_rss_notify($event);

    print "_default : $event\n";

    #print "_default : ", Dumper($args);

#    for my $arg (@$args) {
#        if ( ref $arg eq 'ARRAY' ) {
#            push( @output, '[' . join(' ,', @$arg ) . ']' );
#        }
#        else {
#            push ( @output, "'$arg'" );
#        }
#    }
#    print join ' ', @output, "\n";
    return 0;
}

# IRC RSS Notify
sub irc_rss_notify {
    my ($event) = shift;

    return; # for debugging by yuni

    if ($event eq 'irc_ping') {
        $ping_time++;

        if ($ping_time % 5 == 0) {
            system("perl aggregate.pl");
            warn "Aggregator gogo!";
        }

        if ($ping_time % 7 == 0) {
            warn "Aggregate result";
            my $data = LoadFile("result.yaml");
            foreach my $key (keys %{ $data }) {
                foreach my $feed (@{ $data->{$key} }) {
                    $irc->yield( privmsg => '#perl-kr' => "[ ". $feed->{type} . " ] " . 
                                     $feed->{title}. '<'.($feed->{author} || "Unknown").'> :: '. $feed->{link} );
                }
            }
        }
    }
}

# URL Find : Title Notify
sub irc_urifind_uri {
    my ($who, $channel, $url, $obj, $msg) = @_[ARG0 .. ARG4];
    
    my $ua = LWP::UserAgent->new;
    my $res = $ua->get($url);
    if ($res->is_success) {
        $base_url = $url;
	my $html = scraper {
	    process 'title', title => 'TEXT';
	};
	my $data = $html->scrape(URI->new($url));
	return 0 unless $data->{title};
	my $title = $data->{title};
	$irc->yield( privmsg => $channel => $title );
    }
}
